"""
需求：
    备份指定目录及其下目录树中的文件
        * 遍历目录树
    备份指定日期内发生改动的文件，包括新创建的文件
        * 对比mtime (modified time)
    只备份常规文件
        * 测试文件类型
    压缩备份文件
        * 使用tar和zlib
    定时触发
        * 操作系统层面
"""
import os
import sys
import tarfile
from datetime import datetime, timedelta


class Backup:

    def __init__(self, src_dir, dst_dir, start_time=None, end_time=None):
        if start_time is None or end_time is None:
            now = datetime.now()
            year, month, day = now.timetuple()[:3]
            start_time = datetime(year, month, day, 0, 0, 0)
            end_time = datetime(year, month, day, 23, 59, 59)
        else:
            start_time = datetime.strptime(start_time, '%Y%m%d')
            end_time = datetime.strptime(end_time, '%Y%m%d')
            end_time += timedelta(hours=23, minutes=59, seconds=59)
        self.start_time = start_time.timestamp()
        self.end_time = end_time.timestamp()

        self.src_dir = src_dir
        self.dst_dir = dst_dir

        backup_file_bname = datetime.now().strftime('%Y%m%d%H%M%S') + '.tar.xz'
        self.backup_file = os.path.join(dst_dir, backup_file_bname)
        self.file_names = []

    def collect(self):
        dirs = [self.src_dir]
        for dir in dirs:
            files = os.listdir(dir)
            for file in files:
                path = os.path.join(dir, file)
                if os.path.islink(path):
                    continue
                elif os.path.isdir(path):
                    dirs.append(path)
                elif os.path.isfile(path):
                    if self.time_match(path):
                        self.file_names.append(path)

    def time_match(self, path):
        mtime = os.path.getmtime(path)
        return self.start_time <= mtime <= self.end_time

    def pack(self):
        tar = tarfile.open(self.backup_file, mode='w:xz')
        for file in self.file_names:
            tar.add(file)
        tar.close()

    def work(self):
        self.collect()
        self.pack()


if __name__ == '__main__':
    args = sys.argv[1:]
    if len(args) not in (2, 4):
        bname = os.path.basename(sys.argv[0])
        print('usage: %s src dst [start end]' % bname, file=sys.stderr)
        exit(1)

    src, dst = args[:2]
    if len(args) == 4:
        start, end = args[-2:]
    else:
        start = end = None

    backup = Backup(src, dst, start, end)
    backup.work()
